/**
 * 
 */
package br.org.bertol.mestrado.engine;

import java.io.FileOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.CountDownLatch;

import org.apache.log4j.Logger;
import org.apache.poi.ss.usermodel.Workbook;

import br.org.bertol.mestrado.engine.exception.HeuristicsException;
import br.org.bertol.mestrado.engine.fitness.MutantAnalysis;
import br.org.bertol.mestrado.engine.optimisation.aco.AntColonyOptimization;
import br.org.bertol.mestrado.engine.optimisation.entity.Ant;
import br.org.bertol.mestrado.engine.optimisation.moo.OrdenatePareto;
import br.org.bertol.mestrado.engine.optimisation.moo.ParetoMinMaxDominace;

/**
 * @author contaqualquer
 */
public class EngineAnt extends AbstractSearchEngine<String> {

    /***/
    private final transient float                               threshold;

    /***/
    private final transient List<AntColonyOptimization<String>> resultAnt;

    /***/
    private final transient float                               fEvaporation;

    /***/
    private final transient float                               fMinPheromone;

    /***/
    private final transient float                               fAlpha;

    /***/
    private final transient float                               fBeta;

    /**
     * @param wellThreshoold
     *            Limiar de seleção da roleta
     * @param evaporation
     *            Taxa de evaporação
     * @param minPheromone
     *            Taxa mínima de feromônios
     * @param alpha
     *            Parâmetro alpha
     * @param beta
     *            Parâmetro beta
     */
    public EngineAnt(final CountDownLatch startS, final CountDownLatch stopS,
        final int numEval, final Objective[] objectives, final String storeP,
        final String sID, final float wellThreshoold,
        final float evaporation, final float minPheromone,
        final float alpha, final float beta) {

        super(startS, stopS, numEval, storeP, sID, objectives);

        threshold = wellThreshoold;

        fEvaporation = evaporation;

        fMinPheromone = minPheromone;

        fAlpha = alpha;

        fBeta = beta;

        resultAnt = new ArrayList<AntColonyOptimization<String>>();

    }

    @Override
    public final void run() {
        try {
            // deixa sistema ponto para entrar em ação
            startSystem.await();

            if (verify.isSystemEnable()) {
                Logger.getLogger(this.getClass()).info("Start");

                final List<Ant<String>> ants = new ArrayList<Ant<String>>();

                // cria lista de ants
                for (int i = 0; i < verify.getClasses().size(); i++) {

                    final MutantAnalysis mutantAnalysis = new MutantAnalysis(
                            (ArrayList<String>) verify.getClasses());

                    final Ant<String> formiga = new Ant<String>(fAlpha, fBeta,
                            threshold, mutantAnalysis, verify.getObjectives());

                    ants.add(formiga);
                }

                // [VSCR, OAAN, OLLN, VTWD, ORSN, OLNG, OLSN, OABN, SSWM, STRI]
                /*
                 * final MutantAnalysis mutantAnalysis = new MutantAnalysis(
                 * (ArrayList<String>) verify.getClasses());
                 * 
                 * final Ant<String> formiga = new Ant<String>(fAlpha, fBeta,
                 * threshold, mutantAnalysis, verify.getObjectives());
                 * 
                 * formiga.addClass("VSCR");
                 * formiga.addClass("OAAN");
                 * formiga.addClass("OLLN");
                 * formiga.addClass("VTWD");
                 * formiga.addClass("ORSN");
                 * formiga.addClass("OLNG");
                 * formiga.addClass("OLSN");
                 * formiga.addClass("OABN");
                 * formiga.addClass("SSWM");
                 * formiga.addClass("STRI");
                 * 
                 * 
                 * formiga.calcFitness();
                 */
                Collections.sort(ants, new OrdenatePareto<Ant<String>>(
                        new ParetoMinMaxDominace()));

                // cria colônia de formigas
                final AntColonyOptimization<String> colonyOptimization =
                        new AntColonyOptimization<String>(numIteracoes,
                        ants, fEvaporation, fMinPheromone,
                        (ArrayList<String>) verify.getClasses(),
                        verify.getObjectives());

                initTime = System.currentTimeMillis();

                colonyOptimization.evaluate();

                stopTime = System.currentTimeMillis();

                resultAnt.add(colonyOptimization);

                final List<Ant<String>> list = colonyOptimization
                        .getParetoBorder();

                Collections.sort(list, new OrdenatePareto<Ant<String>>(
                        new ParetoMinMaxDominace()));

                storeResult(list);

                final String fileName = new String(storePath + "/" + systemID
                        + "/resultado_avaliacao_" + systemID + "_ACO.xls");

                final Workbook workbook = getInputStream(fileName);

                getResultSheet(workbook);

                final FileOutputStream out = new FileOutputStream(fileName);

                workbook.write(out);

                out.close();

                Logger.getLogger(this.getClass()).info("End");
            }
        } catch (InterruptedException e) {
            Logger.getLogger(this.getClass()).error(
                                                    "Erro ao executar sistema "
                    + systemID, e);
        } catch (IOException e) {
            Logger.getLogger(this.getClass()).error(
                                                    "Erro ao executar sistema "
                    + systemID, e);
        } catch (HeuristicsException e) {
            Logger.getLogger(this.getClass()).error(
                                                    "Erro ao executar sistema "
                    + systemID, e);
        }

        // notifica main thread
        stopSystem.countDown();
    }
}
